#include "channel.h"
#include "eventloop.h"
#include <cassert>
#include <sys/epoll.h>
#include <utility>

Channel::Channel(EventLoop* loop, int fd) 
: loop_(loop), fd_(fd), events_(0), revents_(0){}

Channel::~Channel() = default;

void Channel::handleEvent(){
    if ((revents_ & EPOLLHUP) && !(revents_ & EPOLLIN)) {
        if (closeCallback_) {
            closeCallback_();
        }
    }

    if (revents_ & EPOLLERR) {
        if (errorCallback_) {
            errorCallback_();
        }
    }

    if (revents_ & (EPOLLIN | EPOLLPRI)) {
        if (readCallback_) {
            readCallback_();
        }
    }

    if (revents_ & EPOLLOUT) {
        if (writeCallback_) {
            writeCallback_();
        }
    }
}

void Channel::setReadCallback(EventCallback cb){
    readCallback_ = std::move(cb);
}

void Channel::setWriteCallback(EventCallback cb){
    writeCallback_ = std::move(cb);
}

void Channel::setCloseCallback(EventCallback cb){
    closeCallback_ = std::move(cb);
}

void Channel::setErrorCallback(EventCallback cb){
    errorCallback_ = std::move(cb);
}

void Channel::enableReading(){
    events_ |= EPOLLIN;
    update();
}

void Channel::disableReading() {
    events_ &= ~EPOLLIN; 
    update();
}

void Channel::enableWrite() {
    events_ |= EPOLLOUT;
    update();
}

void Channel::disableWrite() {
    events_ &= ~EPOLLOUT; 
    update();
}

void Channel::disableAll(){
    events_ = 0;
    update();
}

void Channel::update() {
    assert(loop_ != nullptr);
    loop_->updateChannel(this);
}

void Channel::remove(){
    loop_->removeChannel(this);
}